/***************************************************************************
 *   Copyright (C) 2008 by Rysiek KrÃ³l,,,   *
 *   rysiek@Babylon2   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "imageloader.h"
#include "picturemanager.h"
#include "picturelistwidgetitem.h"
#include "imageloadedevent.h"
#include "saveimageevent.h"

#include <QApplication>
#include <QLabel>
#include <QDesktopWidget>

/**
* class Constructor
*/
ImageLoader::ImageLoader( PictureManager *manager)
        : QThread()
{
    this->manager = manager;
    this->start ( QThread::LowPriority );
    this->goToSleep = true;
    this->size = QApplication::desktop()->size();
    this->connect( this->manager->getItsProperty() , SIGNAL ( propertyChanged(Property::PropertyType) ), this, SLOT ( propertyChangedSlot(Property::PropertyType) ) );
}

/**
* Class Destructor
*/
ImageLoader::~ImageLoader()
{
}

/**
* Main thread method
*/
void ImageLoader::run()
{
    while (true)
    {
        this->waitMutex.lock();
        if (this->goToSleep) this->newActionCondition.wait(&this->waitMutex);
        this->waitMutex.unlock();
        this->goToSleep = true;
        switch (this->currentAction)
        {
        case ImageLoader::GetIndex :
            this->sendIndexedImage();
            this->isCurrentChanged = false;
            break;
        case ImageLoader::GetNext:
            this->sendNextImage();
            this->isCurrentChanged = false;
            break;
        case ImageLoader::GetPrevious:
            this->sendPreviousImage();
            this->isCurrentChanged = false;
            break;
        case ImageLoader::GetCurrent:
            this->sendCurrentImage();
            this->isCurrentChanged = false;
            break;
        case ImageLoader::GetNextAndReload:
            this->sendNextAndReload();
            this->isCurrentChanged = false;
            break;
        case ImageLoader::Turn90:
            this->rotateAndSendImage(90);
            this->isCurrentChanged = true;
            break;
        case ImageLoader::Turn180:
            this->rotateAndSendImage(180);
            this->isCurrentChanged = true;
            break;
        case ImageLoader::Turn270:
            this->rotateAndSendImage(270);
            this->isCurrentChanged = true;
            break;
        case ImageLoader::GetFirstSlide:
            this->sendFirstSlide();
            this->isCurrentChanged = false;
            break;
        case ImageLoader::GetNextSlide:
            this->sendNextSlide();
            this->isCurrentChanged = false;
            break;
        case ImageLoader::GetPreviousSlide:
            this->sendProviousSlide();
            this->isCurrentChanged = false;
            break;
        }
    }
}

/**
* Returning current image Index
*/
int ImageLoader::getCurrentIndex() const
{
    return currentIndex;
}

/**
* Setting current Index
*/
void ImageLoader::setCurrentIndex(int theValue)
{
    currentIndex = theValue;
}

/**
* Sending Indexed Image to the Thread and load other images
*/
void ImageLoader::sendIndexedImage()
{
    PictureListWidgetItem *tmpItem;
    tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex));
    this->actionList.clear();
    this->currentImage.load(tmpItem->getFile().filePath());
    this->currentImage = getScaledImage(this->currentImage);
    QApplication::postEvent ( this->manager,
                              new ImageLoadedEvent ( this->currentImage,
                                                     this->currentIndex,
                                                     this->manager->getListWidget()->count()));

    if ((this->currentIndex+1)<this->manager->getListWidget()->count())
    {
        tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex+1));
        this->nextImage.load(tmpItem->getFile().filePath());
        this->nextImage = getScaledImage(this->nextImage);
    }
    if ((this->currentIndex-1)>0)
    {
        tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex-1));
        if (!tmpItem->getFile().isDir())
        {
            this->previousImage.load(tmpItem->getFile().filePath());
            this->previousImage=getScaledImage(this->previousImage);
        }
    }
}

/**
* returning current Action
*/
ImageLoader::Action ImageLoader::getCurrentAction() const
{
    return currentAction;
}

/**
* Setting  current action variable
*/
void ImageLoader::setCurrentAction(const Action& theValue)
{
    slideMutex.lock();
    this->currentAction = theValue;
    slideMutex.unlock();
}

/**
* Sending next image to the GUI Thread
*/
void ImageLoader::sendNextImage()
{
    PictureListWidgetItem *tmpItem;

    if (this->manager->getItsProperty()->getAutoSaveImages() && !this->actionList.isEmpty())
    {
        tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex));
        QString w = tmpItem->getFile().filePath();
        QApplication::postEvent(this->manager, new SaveImageEvent(this->getActionList(), tmpItem->getFile() ));
    }

    QApplication::postEvent ( this->manager,
                              new ImageLoadedEvent ( this->nextImage,
                                                     ++this->currentIndex,
                                                     this->manager->getListWidget()->count()));
    this->actionList.clear();
    this->previousImage = this->currentImage;
    this->currentImage = this->nextImage;
    if ((this->currentIndex+1)<this->manager->getListWidget()->count())
    {
        tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex+1));
        this->nextImage.load(tmpItem->getFile().filePath());
        this->nextImage=getScaledImage(this->nextImage);
    }
}

/**
* Sending previous image to the GUI Thread
*/
void ImageLoader::sendPreviousImage()
{
    PictureListWidgetItem *tmpItem;

    if (this->manager->getItsProperty()->getAutoSaveImages() && !this->actionList.isEmpty())
    {
        tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex));
        QApplication::postEvent(this->manager, new SaveImageEvent(this->getActionList(), tmpItem->getFile()));
    }
    QApplication::postEvent ( this->manager, 
                              new ImageLoadedEvent ( this->previousImage, 
                                                     --this->currentIndex, 
                                                     this->manager->getListWidget()->count()));
    this->actionList.clear();
    this->nextImage = this->currentImage;
    this->currentImage = this->previousImage;
    if ((this->currentIndex-1)!=0)
    {
        tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex-1));
        if (!tmpItem->getFile().isDir())
        {
            this->previousImage.load(tmpItem->getFile().filePath());
            this->previousImage=getScaledImage(this->previousImage);
        }
    }
}

/**
* Setting goToSleep Flag to False
*/
void ImageLoader::setGoToSleepFalse()
{
    this->goToSleep = false;
}

/**
* Sending current image to the GUI Thread
*/
void ImageLoader::sendCurrentImage()
{
    QApplication::postEvent ( this->manager, new ImageLoadedEvent ( this->currentImage, this->currentIndex));
}

/**
* Zwraca odpowiednio przeskalowany obraz
*/
QImage ImageLoader::getScaledImage(QImage image)
{
    if (!this->manager->getItsProperty()->getShowScalledPictures())
    {
        if (this->size.width()>image.size().width() && this->size.height()>image.size().height()) return image;
    }
    return image.scaled(this->size, Qt::KeepAspectRatio);
}


/**
* Åaduje ponownie wszystkie obrazy
*/
void ImageLoader::reloadImages()
{
    PictureListWidgetItem *tmpItem;
    tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex));
    this->currentImage.load(tmpItem->getFile().filePath());
    this->currentImage = getScaledImage(this->currentImage);

    if ((this->currentIndex+1)<this->manager->getListWidget()->count())
    {
        tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex+1));
        this->nextImage.load(tmpItem->getFile().filePath());
        this->nextImage = getScaledImage(this->nextImage);
    }
    if (this->currentIndex>0)
    {
        tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex-1));
        this->previousImage.load(tmpItem->getFile().filePath());
        this->previousImage = getScaledImage(this->previousImage);
    }

}
/**
* Slot executed, when property is changed
*/
void ImageLoader::propertyChangedSlot(Property::PropertyType typ)
{
    if (typ == Property::ShowScalledPicture)
    {
        this->reloadImages();
    }
}

/**
* Sends next image and reloads all buffers
*/
void ImageLoader::sendNextAndReload()
{
    PictureListWidgetItem *tmpItem;
    QApplication::postEvent ( this->manager, new ImageLoadedEvent ( this->nextImage, this->currentIndex));
    this->currentImage = this->nextImage;
    if ((this->currentIndex+1)<this->manager->getListWidget()->count())
    {
        tmpItem = dynamic_cast<PictureListWidgetItem*> ( this->manager->getListWidget()->item(this->currentIndex+1));
        this->nextImage.load(tmpItem->getFile().filePath());
        this->nextImage=getScaledImage(this->nextImage);
    }
}

/**
* Rotate current image and send it to GUI thread
*/
void ImageLoader::rotateAndSendImage(int degree)
{
    this->actionList.append(this->currentAction);
    QMatrix matrix;
    matrix.rotate(degree);
    this->currentImage = this->currentImage.transformed(matrix);
    this->isCurrentChanged = true;
    QApplication::postEvent ( this->manager, new ImageLoadedEvent ( getScaledImage(this->currentImage), this->currentIndex));
}



/**
* Returns list of actions, that has been perform on current Image
*/
QList< ImageLoader :: Action > ImageLoader::getActionList() const
{
    return actionList;
}

/**
* Returns if current image has changed
*/
bool ImageLoader::getIsCurrentChanged() const
{
    return isCurrentChanged;
}

/**
* Sets FileInfo for next Slide
*/
void ImageLoader::setNextSlide(const QFileInfo& theValue)
{
    slideMutex.lock();
    this->nextSlide = theValue;
    slideMutex.unlock();
}


/**
* Sends next image in SlideShow mode
*/
void ImageLoader::sendNextSlide()
{
    QApplication::postEvent ( this->manager, new ImageLoadedEvent ( this->nextImage, this->currentIndex));
    this->actionList.clear();
    this->previousSlide = this->currentSlide;
    this->currentSlide = this->nextSlide;
    this->previousImage = this->currentImage;
    this->currentImage = this->nextImage;
    this->nextImage.load(this->nextSlide.filePath());
    this->nextImage=getScaledImage(this->nextImage);
}

/**
* Sends first image in SlideShow mode
*/
void ImageLoader::sendFirstSlide()
{
    this->actionList.clear();
    this->currentImage.load(this->currentSlide.filePath());
    this->currentImage=getScaledImage(this->currentImage);
    QApplication::postEvent ( this->manager, new ImageLoadedEvent ( this->currentImage, this->currentIndex));
    this->nextImage.load(this->nextSlide.filePath());
    this->nextImage=getScaledImage(this->nextImage);

    this->previousSlide = this->currentSlide;
    this->previousImage = this->currentImage;
}

/**
* Sets new slide
*/
void ImageLoader::setCurrentSlide(const QFileInfo& theValue)
{
    slideMutex.lock();
    currentSlide = theValue;
    slideMutex.unlock();
}


void ImageLoader::setPreviousSlide(const QFileInfo& theValue)
{
    slideMutex.lock();
    previousSlide = theValue;
    slideMutex.unlock();
}

void ImageLoader::sendProviousSlide()
{
    QApplication::postEvent ( this->manager, new ImageLoadedEvent ( this->previousImage, this->currentIndex));
    this->actionList.clear();
    this->nextSlide = this->currentSlide;
    this->currentSlide = this->previousSlide;

    this->nextImage = this->currentImage;
    this->currentImage = this->previousImage;

    this->previousImage.load(this->previousSlide.filePath());
    this->previousImage=getScaledImage(this->previousImage);
}


QFileInfo ImageLoader::getCurrentSlide() const
{
    return currentSlide;
}



void ImageLoader::setCurrentChangedFalse ()
{
    this->actionList.clear();
    isCurrentChanged = false;
}
